package com.treasure.service.third.service.impl;

import com.alibaba.fastjson.JSON;
import com.treasure.service.commons.lang.util.IdCreater;
import com.treasure.service.commons.lang.util.MD5Util;
import com.treasure.service.commons.lang.util.StringUtil;
import com.treasure.service.commons.lang.util.XMLUtil;
import com.treasure.service.constant.Constants;
import com.treasure.service.constant.GlobalConstant;
import com.treasure.service.domain.TPayData;
import com.treasure.service.domain.TPayLog;
import com.treasure.service.domain.TUserInfo;
import com.treasure.service.dto.AffirmPayResult;
import com.treasure.service.dto.PreparePayResult;
import com.treasure.service.dto.PrepareResult;
import com.treasure.service.enums.PayEnum;
import com.treasure.service.mapper.TPayDataMapper;
import com.treasure.service.mapper.TPayLogMapper;
import com.treasure.service.mapper.TUserInfoMapper;
import com.treasure.service.third.handler.PrepayIdRequestHandler;
import com.treasure.service.third.properties.PayProperties;
import com.treasure.service.third.service.PayService;
import com.treasure.service.third.utils.RestClient;
import com.treasure.service.third.utils.WXUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * @Auther: panxinwen
 * @Date: 2018/10/21 13:14
 * @Description:
 */
@Service
public class PayServiceImpl implements PayService {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private PayProperties payProperties;

    @Autowired
    private TUserInfoMapper tUserInfoMapper;

    @Autowired
    private TPayLogMapper tPayLogMapper;

    @Autowired
    private TPayDataMapper tPayDataMapper;

    @Autowired
    private RestClient restClient;

    @Value("${treasure.rest.service.biz}")
    private String bizUrl;

    @Override
    public PrepareResult createPayOrder(Integer payType,Long bizId, PayEnum payEnum,
                                        Long total_fee,Long userId,String clientIp) throws Exception {

        // 获取生成预支付订单的请求类
        PrepayIdRequestHandler prepayReqHandler = new PrepayIdRequestHandler();
//        prepayReqHandler.setParameter("body", payEnum.getBody());//商品描述
        prepayReqHandler.setParameter("body", "购买会员");//商品描述
        prepayReqHandler.setParameter("attach", payEnum.getCode()+"-"+bizId);//商户自定义数据：业务类型-业务流水号
        prepayReqHandler.setParameter("notify_url", payProperties.getNotify_url()+payEnum.getNotify());//异步接收微信支付结果通知的回调地址，通知url必须为外网可访问的url，不能携带参数。
        prepayReqHandler.setParameter("total_fee", 1);//订单总金额，单位为分
        prepayReqHandler.setParameter("out_trade_no", IdCreater.getLongId());//订单号
//        prepayReqHandler.setParameter("product_id", PayEnum.getCode());//保留字段
        TPayLog tPayLog = new TPayLog();
        tPayLog.setOrderNo(bizId);
        TUserInfo tUserInfo = tUserInfoMapper.selectByPrimaryKey(userId);
        tPayLog.setUserId(userId);
        tPayLog.setBizType(payEnum.getCode());
        return sendPayOrder(getPayOrder(prepayReqHandler,payType,clientIp),tUserInfo.getOpenId(),tPayLog,payType);
    }

    /**
     * 微信支付结果通知
     * 此处需改造：做重复通知处理(微信通知失败机制，在未收到服务器响应或响应超时，微信会重复推送，详细请参照微信公众号 支付文档)
     * @param affirmPayResult
     */
    @Override
    public void getnotify(AffirmPayResult affirmPayResult) {



    }

    @Override
    public int updateByPrimaryKeySelective(TPayLog tPayLog) {
        return tPayLogMapper.updateByPrimaryKeySelective(tPayLog);
    }

    @Override
    public void notify(AffirmPayResult affirmPayResult) {
        // 若支付成功，则告知微信服务器收到通知
        if (affirmPayResult.getIs_returned()) {
            TPayLog tPayLog = tPayLogMapper.selectByPrimaryKey(Long.parseLong(affirmPayResult.getOut_trade_no()));
            TPayData tPayData = new TPayData();
            Integer status=1;
            tPayData.setId(Long.parseLong(affirmPayResult.getOut_trade_no()));
            tPayData.setCallBackXml(affirmPayResult.getXml());
            tPayLog.setCallBackReturnCode(affirmPayResult.getReturn_code());
            tPayLog.setCallBackReturnMsg(affirmPayResult.getReturn_msg());
            tPayLog.setTransactionId(affirmPayResult.getTransaction_id());
            tPayLog.setStatus(Constants.PayStatus.SUCCESS);
            tPayLog.setCallBackTime(new Date());

            boolean isSuccess = StringUtil.isEqual(affirmPayResult.getResult_code(), Constants.PayStatus.W_SUCCESS);
            //2、处理支付订单成功
            if (!isSuccess) {
                status=2;
                tPayLog.setCallBackErrCode(affirmPayResult.getErr_code());
                tPayLog.setCallBackErrCodeDes(affirmPayResult.getErr_code_des());
                tPayLog.setStatus(Constants.PayStatus.FAIL);
            }
            tPayLogMapper.updateByPrimaryKeySelective(tPayLog);
            tPayDataMapper.updateByPrimaryKeySelective(tPayData);
            //支付成功后退职业务端
            try {

                Map<String,Object> map = new HashMap<>();
                map.put("bizId",tPayLog.getOrderNo());
                map.put("status",status);
                map.put("userId",tPayLog.getUserId());

                restClient.post(bizUrl+"/userInfo/v1/dredgeMemberCallBack",map,String.class);

            }catch (Exception e){

                logger.error("支付结果通知业务端异常：{}",e);

            }
        }

    }

    private PrepayIdRequestHandler getPayOrder(PrepayIdRequestHandler prepayReqHandler,Integer payType,String clientIp) {

//        prepayReqHandler.setParameter("attach", PayEnum.CHARGE.getCode());//业务类型
        prepayReqHandler.setParameter("product_id", PayEnum.BUY_MEMBER.getCode());//保留字段
        prepayReqHandler.setParameter("appid", payProperties.getAppid());//微信支付分配的公众账号ID（企业号corpid即为此appId）
        prepayReqHandler.setParameter("mch_id", payProperties.getMch_id());//微信支付分配的商户号
        prepayReqHandler.setParameter("device_info", "WEB");//自定义参数，可以为终端设备号(门店号或收银设备ID)，PC网页或公众号内支付可以传"WEB"
        prepayReqHandler.setParameter("nonce_str",WXUtil.getNonceStr());//随机字符串，长度要求在32位以内。
//        prepayReqHandler.setParameter("detail", payProperties.getDescribe());//商品详细描述，对于使用单品优惠的商户，改字段必须按照规范上传，详见

        prepayReqHandler.setParameter("spbill_create_ip", payType==1?"47.94.216.45":clientIp);//APP和网页支付提交用户端ip，Native支付填调用微信支付API的机器IP
//        prepayReqHandler.setParameter("time_start", WXUtil.getTimeStamp());
//        prepayReqHandler.setParameter("trade_type", "JSAPI");//JSAPI 公众号支付 NATIVE 扫码支付
        prepayReqHandler.setParameter("trade_type", payType==1?"JSAPI":"MWEB");//JSAPI 公众号支付 NATIVE 扫码支付
        prepayReqHandler.setParameter("limit_pay", "no_credit");//上传此参数no_credit--可限制用户不能使用信用卡支付
        if (payType.intValue() == 2){
            prepayReqHandler.setParameter("scene_info", "{\"h5_info\": {\"type\":\"Wap\",\"wap_name\": \"生财有道\",\"wap_url\": \"http://hbweb.jingyugg.com/\"}}");//场景信息
        }

        return prepayReqHandler;
    }

    private PrepareResult sendPayOrder(PrepayIdRequestHandler prepayReqHandler, String openid, TPayLog tPayLog ,Integer payType) throws Exception {

        if (payType.intValue()==1){
            prepayReqHandler.setParameter("openid", openid);
        }
        prepayReqHandler.setParameter("sign", prepayReqHandler.createMD5Sign());
        prepayReqHandler.setGateUrl(payProperties.getGateurl());

        TPayData tPayData = new TPayData();
        String params = prepayReqHandler.getParameters();
        tPayLog.setId(StringUtil.objToLong(prepayReqHandler.getAllParameters().get("out_trade_no")));
        tPayLog.setApplicationType(2);
        tPayLog.setAccountType(1);
        tPayLog.setCreateTime(new Date());
        tPayData.setReqXml(params);
        tPayData.setId(tPayLog.getId());
        tPayLog.setStatus(0);
        tPayLog.setRequestType(0);
        tPayLogMapper.insert(tPayLog);
        tPayDataMapper.insert(tPayData);

        logger.info("预支付报文：{}",params);

        String result = prepayReqHandler.sendPrepay(params);
        tPayData.setReqReturnXml(result);

        logger.info("预支付返回报文：{}",result);

        Map map= XMLUtil.doXMLParse(result);
        PreparePayResult preparePayResult = JSON.parseObject(JSON.toJSONString(map),PreparePayResult.class);
        tPayLog.setReqReturnCode(preparePayResult.getReturn_code());
        tPayLog.setReqReturnMsg(preparePayResult.getReturn_msg());
        tPayLog.setStatus(2);
        tPayLog.setReqReturnTime(new Date());

        PrepareResult prepareResult = new PrepareResult();

        prepareResult.setReturn_code(preparePayResult.getReturn_code());
        prepareResult.setReturn_msg(preparePayResult.getReturn_msg());
        prepareResult.setResult_code(preparePayResult.getResult_code());
        // 若获取prepayid成功，将相关信息返回客户端
        if (GlobalConstant.SUCCESS.equals(preparePayResult.getResult_code())&& GlobalConstant.SUCCESS.equals(preparePayResult.getReturn_code())) {
            tPayLog.setStatus(1);
            Object timestamp = prepayReqHandler.getAllParameters().get("time_start");
            Object nonce_str = prepayReqHandler.getAllParameters().get("nonce_str");
            String prepayid = preparePayResult.getPrepay_id();
            //此处生成订单
//            String signs = "appid=" + payProperties.getAppid() + "&timeStamp=" + timestamp + "&nonceStr="+nonce_str+"&package=prepay_id="+prepayid+ "&signType=MD5";

            SortedMap parameters = new TreeMap();
            parameters.put("appId",payProperties.getAppid());
            parameters.put("timeStamp",timestamp);
            parameters.put("nonceStr",nonce_str);
            parameters.put("package","prepay_id="+prepayid);
            parameters.put("signType","MD5");

            prepareResult.setAppId(payProperties.getAppid());
            prepareResult.setNonceStr(nonce_str+"");
            prepareResult.setPrepayid(prepayid);
            prepareResult.setPaySign(MD5Util.MD5Encode(parameters, "utf8").toUpperCase());
            prepareResult.setTimeStamp(timestamp+"");

            prepareResult.setPackageValue("prepay_id="+prepayid);

            if (payType.intValue() == 2){
                prepareResult = new PrepareResult();
                prepareResult.setMwebUrl(preparePayResult.getMweb_url());
            }

        }

        tPayLogMapper.updateByPrimaryKeySelective(tPayLog);
        tPayDataMapper.updateByPrimaryKeySelective(tPayData);

        logger.info("调用微信预支付返回前端数据：{}",JSON.toJSONString(prepareResult));

        return prepareResult;

    }

}
